/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { defineComponent, computed, ref, onMounted, onBeforeMount, withModifiers } from 'vue';
import type { SetupContext } from 'vue';
import { calculatorProps, CalculatorProps } from './calculator.props';
import { useCalculator } from './composition/use-calculator';
import './calculator.css';

export default defineComponent({
    name: 'FCalculator',
    props: calculatorProps,
    emits: [
    ] as (string[] & ThisType<void>) | undefined,
    setup(props: CalculatorProps, context: SetupContext) {
        /** 操作步骤显示区 */
        const stepEl = ref<HTMLElement | null>();
        /** 计算结果显示区 */
        const resultEl = ref<HTMLElement | null>();
        /** 按钮区 */
        const symbolEl = ref<HTMLElement | null>();
        const preEl = ref<HTMLElement | null>();
        const leftEl = ref<HTMLElement | null>();
        const rightEl = ref<HTMLElement | null>();

        /** 操作步骤缓存 */
        let stepInputCache: any = '';
        /** 结果缓存 */
        let resultInputCache: any = '0';
        /** 记录加减乘除的数字 */
        let preNumber: any[] = [];
        /** 记录加减乘除符号 */
        let preOperator: any[] = [];
        /** 记录能否追加运算或者数字是追加还是覆盖 */
        let firstInputToken: boolean;
        let equalToken: boolean;

        const { plus, minus, times, divide } = useCalculator();

        function calculateWidth() {
            if (stepEl.value && preEl.value && leftEl.value && rightEl.value) {
                if (stepEl.value.scrollWidth > preEl.value.offsetWidth) {
                    leftEl.value.style.display = 'block';
                    rightEl.value.style.display = 'block';
                } else {
                    leftEl.value.style.display = 'none';
                    rightEl.value.style.display = 'none';
                }
            }
        }

        /**
         * @param value 设置步骤显示区的内容
         */
        function setStepInput(value: any) {
            if (stepEl.value) {
                stepEl.value.innerHTML = value;
            }
        }

        /**
         *
         * @param value 设置结果示区的内容
         */
        function setResultInput(value: any) {
            if (resultEl.value) {
                resultEl.value.innerHTML = value;
            }
        }

        /**
         * 步骤操作视窗中，最后显示的是否是操作符
         */
        function stepInputEndIsOperator() {
            return stepInputCache.lastIndexOf('+') !== -1 ||
                stepInputCache.lastIndexOf('-') !== -1 ||
                stepInputCache.lastIndexOf('×') !== -1 ||
                stepInputCache.lastIndexOf('÷') !== -1;
        }

        /**
         * 加减乘除运算
         * @param f 第一个数字
         * @param s 第二个数字
         * @param o 操作符
         */
        function calculate(f: number, s: number, o: string) {
            let result = 0;
            f = Number(f);
            s = Number(s);
            switch (o) {
            case '+':
                result = plus(f, s);
                break;
            case '-':
                result = minus(f, s);
                break;
            case '×':
                result = times(f, s);
                break;
            case '÷':
                result = divide(f, s);
                break;
            }
            return result;
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function numberClick(val: any) {
            if ((resultInputCache.indexOf('0') === 0 && resultInputCache.indexOf('.') === -1) || firstInputToken === true) {
                resultInputCache = val;
            } else {
                resultInputCache += val;
            }
            firstInputToken = false;
            equalToken = false;
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function dotClick(val: any) {
            if (firstInputToken === true) {
                resultInputCache = '0' + val;
            } else if (resultInputCache.indexOf('.') === -1) {
                resultInputCache += val;
            }
            firstInputToken = false;
            equalToken = false;
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function pnClick() {
            if (resultInputCache.indexOf('-') === -1 && resultInputCache !== '0') {
                resultInputCache = "-" + resultInputCache;
            } else if (resultInputCache.indexOf('-') > -1 && resultInputCache !== '0') {
                resultInputCache = resultInputCache.substring(1);
            }
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function operatorClick(val: any) {
            if (preNumber.length < 2 && (firstInputToken !== true || equalToken === true)) {
                resultInputCache = parseFloat(resultInputCache) + '';
                stepInputCache = stepInputCache + ' ' + resultInputCache + ' ' + val;
                preNumber.push(resultInputCache);
                preOperator.push(val);
                firstInputToken = true;
            } else if (preNumber.length < 2 && stepInputEndIsOperator()) {
                stepInputCache = stepInputCache.substring(0, stepInputCache.length - 1) + '' + val;
                preOperator.push(val);
            }

            if (preNumber.length === 2) {
                const operator = preOperator[preOperator.length - 2];
                if (preNumber[1] === '0' && operator === '÷') {
                    preNumber = [];
                    resultInputCache = '除数不能为零';
                    stepInputCache = '';
                    firstInputToken = true;
                    return;
                }
                const res = calculate(preNumber[0], preNumber[1], operator);
                preNumber = [];
                preNumber.push(res);
                resultInputCache = res + '';
                firstInputToken = true;
            }
            // cdr.detectChanges();
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function equalClick() {
            if (preNumber.length > 0) {
                const operator = preOperator.pop();
                if (resultInputCache === '0' && operator === '÷') {
                    preNumber = [];
                    resultInputCache = '除数不能为零';
                    stepInputCache = '';
                    firstInputToken = true;
                    equalToken = true;
                    return;
                }
                const res = calculate(preNumber[0], resultInputCache, operator);
                preNumber = [];
                resultInputCache = res + '';
                stepInputCache = '';
                firstInputToken = true;
                equalToken = true;
            }
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function ceClick() {
            resultInputCache = '0';
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function cClick() {
            resultInputCache = '0';
            stepInputCache = '';
            firstInputToken = true;
            preNumber = [];
            preOperator = [];
        }

        /**
         * 点击相关的按钮操作
         * @param val
         */
        function backClick() {
            resultInputCache = resultInputCache.length > 1 ?
                resultInputCache.substring(0, resultInputCache.length - 1) : '0';
        }

        const calculatorId = computed(() => {
            const id = (Math.floor(Math.random() * 1000)).toString();
            return `fv-calculator-main${id}`;
        });

        function scrollLeftIncrease(e: any) {
            if (stepEl.value) {
                stepEl.value.scrollLeft += 50;
            }
        }

        function scrollLeftDecrease(e: any) {
            if (stepEl.value) {
                stepEl.value.scrollLeft -= 50;
            }
        }

        function clickEvent(e: any) {
            if (symbolEl.value) {
                if (!symbolEl.value.contains(e.target)) {
                    return;
                }
            }
            const val = e.target.innerHTML;

            switch (val) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                numberClick(val);
                break;
            case '.':
                dotClick(val);
                break;
            case '±':
                pnClick();
                break;
            case '+':
            case '-':
            case '×':
            case '÷':
                operatorClick(val);
                break;
            case '=':
                equalClick();
                break;
            case 'CE':
                ceClick();
                break;
            case 'C':
                cClick();
                break;
            case 'Back':
                backClick();
                break;
            }

            setStepInput(stepInputCache);
            setResultInput(resultInputCache);
        }

        onBeforeMount(() => {

        });

        onMounted(() => {
            stepEl.value = document.getElementById(calculatorId.value)?.querySelector('#fv-calculator-pre-step');
            resultEl.value = document.getElementById(calculatorId.value)?.querySelector('#fv-calculator-show-input');
            symbolEl.value = document.getElementById(calculatorId.value)?.querySelector('#fv-calculator-num-symbol');
            preEl.value = document.getElementById(calculatorId.value)?.querySelector('.fv-calculator-pre');
            leftEl.value = document.getElementById(calculatorId.value)?.querySelector('.fv-calculator-pre-left');
            rightEl.value = document.getElementById(calculatorId.value)?.querySelector('.fv-calculator-pre-right');
            calculateWidth();
        });
        return () => {
            return (
                <>
                    <div
                        class="fv-calculator-standard-main"
                        id={calculatorId.value}
                        onMousedown={withModifiers((payload: MouseEvent) => clickEvent(payload), ['prevent'])}
                        onTouchstart={withModifiers((payload: TouchEvent) => clickEvent(payload), ['prevent'])}
                    >
                        <div class="fv-calculator-title">计算器</div>
                        {/* 结果显示区域 */}
                        <div class="fv-calculator-result">
                            {/* 显示类型信息 */}
                            <div class="fv-calculator-type" id="fv-calculator-show-bar">
                                Standard
                            </div>
                            {/* 上一步的结果 */}
                            <div class="fv-calculator-pre">
                                <div class="fv-calculator-pre-left" style="display:none;"
                                    onMousedown={withModifiers((payload: MouseEvent) => scrollLeftDecrease(payload), ['prevent'])}
                                    onTouchstart={withModifiers((payload: TouchEvent) => scrollLeftDecrease(payload), ['prevent'])}
                                >&lt;</div>
                                <div class="fv-calculator-pre-content" id="fv-calculator-pre-step">
                                </div>
                                <div class="fv-calculator-pre-right" style="display:none;"
                                    onMousedown={withModifiers((payload: MouseEvent) => scrollLeftIncrease(payload), ['prevent'])}
                                    onTouchstart={withModifiers((payload: TouchEvent) => scrollLeftIncrease(payload), ['prevent'])}
                                >&gt;</div>
                            </div>
                            {/* 第二个/运算结果 */}
                            <div class="fv-calculator-result-out">
                                <div class="fv-calculator-second" id="fv-calculator-show-input">0</div>
                            </div>
                        </div>
                        {/* 数字和符号 */}
                        <ul id="fv-calculator-num-symbol">
                            <li value="37" class="fv-calculator-letter">CE</li>
                            <li value="38" class="fv-calculator-letter">C</li>
                            <li value="39" class="fv-calculator-letter">Back</li>
                            <li value="16" class="fv-calculator-operator">÷</li>
                            <li class="fv-calculator-number" value="7">7</li>
                            <li class="fv-calculator-number" value="8">8</li>
                            <li class="fv-calculator-number" value="9">9</li>
                            <li value="15" class="fv-calculator-operator">×</li>
                            <li class="fv-calculator-number" value="4">4</li>
                            <li class="fv-calculator-number" value="5">5</li>
                            <li class="fv-calculator-number" value="6">6</li>
                            <li value="14" class="fv-calculator-operator">-</li>
                            <li class="fv-calculator-number" value="1">1</li>
                            <li class="fv-calculator-number" value="2">2</li>
                            <li class="fv-calculator-number" value="3">3</li>
                            <li value="13" class="fv-calculator-operator">+</li>
                            <li value="11">±</li>
                            <li class="fv-calculator-number" value="0">0</li>
                            <li value="10">.</li>
                            <li value="12" class="fv-calculator-operator">=</li>
                        </ul>
                    </div>
                </>
            );
        };
    }
});
